package org.bluedream.core.module.sys.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.bluedream.comm.base.TreeServiceImpl;
import org.bluedream.comm.utils.ReflexUtil;
import org.bluedream.core.module.sys.entity.Menu;
import org.bluedream.core.module.sys.entity.RoleRelation;
import org.bluedream.core.module.sys.entity.User;
import org.bluedream.core.module.sys.service.org.OrgRelationService;
import org.bluedream.core.utils.SpringUtil;
import org.bluedream.core.utils.UserUtil;
import org.bluedream.core.utils.YmlRead;
import org.bluedream.core.module.sys.dao.MenuDao;
import org.bluedream.comm.utils.EmptyUtil;
import org.bluedream.comm.utils.EncryptUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@DS("master")
@Transactional(
        readOnly = true
)
public class MenuService extends TreeServiceImpl<MenuDao , Menu> implements IService<Menu> {
    private static final Logger logger = LoggerFactory.getLogger(MenuService.class);

    @Resource
    private RoleService roleService;

    @Resource
    private RoleRelationService roleRelationService;

    @Resource
    private OrgRelationService orgRelationService;

    /**
     * 获取树结构数据
     * @param excludeCode 排除的code
     * @param isShowCode 是否显示编码（true or 1：显示在左侧；2：显示在右侧；false or null：不显示）
     * @return
     */
    public List<Map<String , Object>> treeData(String excludeCode , String isShowCode){
        return super.treeData(excludeCode , isShowCode , new Menu());
    }

    public List<Map<String , Object>> treeData(String excludeCode , String isShowCode , List<Menu> list){
        return super.treeData(excludeCode , isShowCode , new Menu() , list);
    }

    public List<Map<String , Object>> treeData(String excludeCode , String isShowCode , List<Menu> source , List<Menu> isChecked){
        return super.treeData(excludeCode , isShowCode , source , isChecked);
    }

    public List<Map<String , Object>> menuTreeData(List<Menu> menus){
        List<Map<String , Object>> mapList = new ArrayList<>();
        getMenuTreeDataList(mapList, menus);
        return mapList;
    }

    private void getMenuTreeDataList(List<Map<String, Object>> mapList, List<Menu> list) {
        for (Menu c1 : list
        ) {
            if (!Menu.STATUS_NORMAL.equals(c1.getStatus())) {
                continue;
            }
            if (!"1".equals(c1.getMenuType())) {
                continue;
            }
            if ("0".equals(c1.getIsShow())) {
                continue;
            }
            String basePath = (String) YmlRead.getValue("application.yml", "adminPath");
            Map<String, Object> map = new HashMap<>();
            map.put("id", c1.getId());
            map.put("pId", c1.getParentCode());
            map.put("name", c1.getTreeName());
            map.put("menuHref", EmptyUtil.isEmpty(c1.getMenuHref()) ? "" : basePath + c1.getMenuHref());
            map.put("menuIcon", c1.getMenuIcon());
            map.put("treeSorts" , c1.getTreeSorts());
            map.put("isTreeLeaf" , "1".equals(c1.getTreeLeaf()));
            map.put("isParent" , "0".equals(c1.getTreeLeaf()));
            map.put("isRoot" , "0".equals(c1.getTreeCode()));
            mapList.add(map);
        }
    }

    /**
     * 不做任何条件判断，返回所有菜单数据
     * @return
     */
    public List<Menu> getALLMenus(){
        return baseMapper.getAllMenus(super.orderByString(new Menu()));
    }

    /**
     * 返回某用户所拥有的菜单明细数据
     * @param userId
     * @param orgId
     * @return
     */
    public List<Menu> getMenusByUserAndOrg(String userId , String orgId){
        return baseMapper.getMenusByLoginUserAndLoginOrg(userId , orgId , super.orderByString(new Menu()));
    }

    public List<Menu> getMenusByRole(String roleId){
        return baseMapper.getMenusByRole(roleId , super.orderByString(new Menu()));
    }

    /**
     * 返回登录用户在登录组织下所拥有的菜单明细数据
     * 1.登录用户 = system，返回所有菜单明细
     * @return
     */
    public List<Menu> getMenusByLoginUserAndLoginOrg(){
        if (UserUtil.isSystem()){
            return this.getALLMenus();
        }else {
            return this.getMenusByUserAndOrg(UserUtil.getLoginInfo().getId() , UserUtil.getLoginOrgCode());
        }
    }

    /**
     * 返回登录用户的菜单treeData结构
     * @return
     */
    public List<Map<String , Object>> getMenuTreeDataByLoginUserAndOrg(int index){
        List<Menu> menus = this.getMenusByLoginUserAndLoginOrg();

        if (menus.size() > 0){
            switch (index){
                case 0:
                    return this.menuTreeData(menus);
                case 1:
                    return this.treeData(null , null , menus);
            }

        }
        return null;
    }

    public List<Map<String , Object>> getMenusTreeDataByRole(String roleId){
        List<Menu> menus = this.getMenusByRole(roleId);
        if (menus.size() > 0){
            return this.menuTreeData(menus);
        }
        return null;
    }

    /**
     * 创建并初始化下一节点信息
     * 0.前端数据仅包含：parentCode、id
     * 1.通过parentCode
     *  1.1 获取父级节点最末节点对象last数据。默认返回null
     *  1.2 获取新的父级节点company对象，默认id = “0”
     *  1.3 如果id ！= null ， 初始化对象
     * 2.新增节点：初始化treeCode：如果 last不为空，则+1。如果为空，但是父级对象不为空，则父级treeCode+ 001
     * 3.编辑节点：如果父级节点无变化，则不更新treeSort排序数据，否则更新
     * @param menu
     * @return
     */
    public Menu createNextNode(Menu menu){
        return super.createNextNode(menu , "menu_code" , "tree_sorts" , "tree_sort");
    }

    public IPage<Menu> findPage(Menu menu){
        return super.findPage(menu , null , "tree_Sorts" , "tree_Sort");
    }

    @Transactional(
            readOnly = false,
            rollbackFor = Exception.class
    )
    public boolean save(Menu entity) {
        try {
            boolean isNewRecord = super.getIsNewRecord(entity , "menu_code" , "getTreeCode");

            entity.setIsNewRecord(isNewRecord);
            if (EmptyUtil.isNoEmpty(entity.getMenuHref())){
                String[] var1 = entity.getMenuHref().split("/");
                StringBuilder var2 = new StringBuilder();

                for (int i = 1; i < var1.length && var1.length > 1; i++) {
                    if (i == 1){
                        var2.append(var1[i]);
                    }else {
                        var2.append(toUpperCase(var1[i]));
                    }
                }
                String menuTarget = var2.toString();
                entity.setMenuTarget(menuTarget);
            }
            return super.save(entity);
        }catch (Exception e){
            e.printStackTrace();
            logger.error("保存菜单信息失败，错误信息：" + e.getMessage());
            //todo:@Transactional和try catch捕获异常会让注解失效
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
    }

    private String toUpperCase(String str){
        char[] chars = str.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] = (char)(chars[0] - 32);
        }
        return String.valueOf(chars);
    }

    @Override
    public Menu getById(Serializable id) {
        if (EmptyUtil.isEmpty(id)){
            return new Menu();
        }else {
            Menu menu = super.getById(id);
            if (!"0".equals(menu.getParentCode())){
                menu.setParent(super.getById(menu.getParentCode()));
            }
            return menu;
        }
    }

    @Override
    @Transactional(
            readOnly = false,
            rollbackFor = Exception.class
    )
    public boolean delete(Menu entity) {
        try {
            //删除角色-关系表中的菜单
            QueryWrapper<RoleRelation> roleRelationQueryWrapper = new QueryWrapper<>();
            roleRelationQueryWrapper.eq("type" , "menu");
            roleRelationQueryWrapper.eq("entity_id" , entity.getId());
            roleRelationService.remove(roleRelationQueryWrapper);
            super.delete(entity);
        }catch (Exception e){
            e.printStackTrace();
            logger.error(e.getMessage());
            //todo:@Transactional和try catch捕获异常会让注解失效
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
        return true;
    }
}
